package br.inf.mfpo.fra4and.activities;

import android.app.AlertDialog;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import br.inf.mfpo.fra4and.R;

/**
 * Activity para edição de dados
 * 
 * @author MarcosFPo
 * 
 */
public abstract class Fra4AndEditActivity extends Fra4AndActivity {

	/**
	 * Limpa os campos da tela
	 */
	protected abstract void clear();

	/**
	 * Cria um ContentValues usado para gravação dos dados
	 * 
	 * @return
	 */
	protected abstract ContentValues getContentValues();

	/**
	 * Cria um ContentValues com os valores iniciais a serem preenchidos
	 * 
	 * @return
	 */
	protected abstract ContentValues getInitialValues();

	/**
	 * Cria um ContentValues a partir do estado da Activity, para substituir os
	 * valores iniciais
	 * 
	 * @return
	 */
	protected abstract ContentValues getRestoredValues();

	/**
	 * Carrega os dados na tela
	 * 
	 * @param cursor
	 */
	protected abstract void populateFields(Cursor cursor);

	/**
	 * Valida os campos antes de gravar
	 * 
	 * @return
	 */
	protected abstract boolean validateFields();

	/**
	 * Preserva o estado atual da Activity
	 */
	protected abstract void keepState();

	/**
	 * Define o título da Activity em caso de inserção
	 * 
	 * @return
	 */
	protected abstract int getInsertTitle();

	/**
	 * Define o título da Activity em caso de alteração
	 * 
	 * @return
	 */
	protected abstract int getEditTitle();

	/**
	 * Define a projeção do Cursor que alimentará a Activity
	 * 
	 * @return
	 */
	protected abstract String[] getProjection();

	private Cursor cursor;
	private Button btnSave;
	private Button btnCancel;
	private boolean insert = false;
	private Uri uri;
	private int createMessage;
	private int updateMessage;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		final Intent intent = getIntent();
		String action = intent.getAction();
		if (action.equals(Intent.ACTION_INSERT)) {
			setTitle(getInsertTitle());
			setInsert(true);
			ContentValues values = savedInstanceState == null ? getInitialValues() : getRestoredValues();
			uri = getContentResolver().insert(intent.getData(), values);
			if (uri == null) {
				Log.e(getClass().getSimpleName(), "Failed to insert new category into " + intent.getData());
				return;
			}
		} else if (action.equals(Intent.ACTION_EDIT) || action.equals(Intent.ACTION_VIEW)) {
			setTitle(getEditTitle());
			uri = intent.getData();
		} else {
			Log.e(getClass().getSimpleName(), "Unknown action, exiting");
			finish();
			return;
		}

		cursor = managedQuery(uri, getProjection(), null, null, null);

		final Intent result = new Intent();
		result.setData(uri);
		setResult(RESULT_OK, result);
	}

	@Override
	protected void onResume() {
		super.onResume();
		if (cursor != null && cursor.moveToFirst()) {
			populateFields(cursor);
			keepState();
		} else {
			showNotification(R.string.error_loading_data);
		}
	}

	@Override
	protected void onPause() {
		super.onPause();
		save();
	}

	/**
	 * Retorna uri passada por parâmetro na chamada da Activity
	 * 
	 * @param uriKey
	 * @return
	 */
	protected Uri getExtraUri(Uri uriKey) {
		Uri result = uriKey;
		final Bundle extras = getIntent().getExtras();
		final String key = uriKey.getPathSegments().get(0);
		if (extras != null && extras.containsKey(key)) {
			String id = extras.getString(key);
			result = ContentUris.withAppendedId(uriKey, Long.parseLong(id));
		}
		return result;
	}

	protected Button getBtnSave() {
		return btnSave;
	}

	/**
	 * Define o botão de salvar
	 * 
	 * @param id
	 */
	protected void setBtnSave(int id) {
		btnSave = (Button) findViewById(id);
		btnSave.setOnClickListener(btnSaveClickListener);
	}

	protected Button getBtnCancel() {
		return btnCancel;
	}

	/**
	 * Define o botão de cancelar
	 * 
	 * @param id
	 */
	protected void setBtnCancel(int id) {
		this.btnCancel = (Button) findViewById(id);
		this.btnCancel.setOnClickListener(btnCancelClickListener);
	}

	protected Cursor getCursor() {
		return cursor;
	}

	/**
	 * Define a mensagem após inserção
	 * 
	 * @param createMessage
	 */
	protected void setCreateMessage(int createMessage) {
		this.createMessage = createMessage;
	}

	/**
	 * Define a mensagem após alteração
	 * 
	 * @param updateMessage
	 */
	protected void setUpdateMessage(int updateMessage) {
		this.updateMessage = updateMessage;
	}

	/**
	 * Retorna se Activity está com ação de inserção
	 * 
	 * @return
	 */
	protected boolean isInsert() {
		return insert;
	}

	protected void setInsert(boolean insert) {
		this.insert = insert;
	}

	protected Uri getUri() {
		return uri;
	}

	/**
	 * Apaga o registro
	 */
	protected void delete() {
		if (cursor != null) {
			cursor.close();
			cursor = null;
			getContentResolver().delete(uri, null, null);
			clear();
		}
	}

	/**
	 * Cancela a edição
	 */
	protected void cancel() {
		if (cursor != null) {
			if (!isInsert()) {
				cursor.close();
				cursor = null;
				getContentResolver().update(uri, getRestoredValues(), null, null);
			} else {
				delete();
			}
		}
		setResult(RESULT_CANCELED);
		showNotification(R.string.canceled);
		finish();
	}

	/**
	 * Grava os dados
	 */
	protected void save() {
		if (cursor != null) {
			if (isInsert() && !isFinishing()) {
				keepState();
				delete();
			} else {
				getContentResolver().update(uri, getContentValues(), null, null);
			}

			if (isFinishing()) {
				if (isInsert()) {
					showNotification(createMessage);
				} else {
					showNotification(updateMessage);
				}
			}
		}
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK) {
			AlertDialog.Builder questionBuilder = new AlertDialog.Builder(this);
			questionBuilder.setTitle(android.R.string.dialog_alert_title);
			questionBuilder.setMessage(getString(R.string.save_cancel_question));
			questionBuilder.setIcon(android.R.drawable.ic_dialog_alert);
			questionBuilder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int which) {
					if (validateFields())
						finish();
				}
			});
			questionBuilder.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int which) {
					cancel();
				}
			});
			questionBuilder.create().show();
			return true;
		} else {
			return super.onKeyDown(keyCode, event);
		}
	}

	private OnClickListener btnCancelClickListener = new OnClickListener() {
		@Override
		public void onClick(View v) {
			onBtnCancelClick(v);
		}
	};

	private OnClickListener btnSaveClickListener = new OnClickListener() {
		@Override
		public void onClick(View v) {
			onBtnSaveClick(v);
		}
	};

	/**
	 * Sobrescreva caso queira mudar o comportamento do botão de salvar
	 * 
	 * @param v
	 */
	protected void onBtnSaveClick(View v) {
		if (validateFields())
			finish();
	}

	/**
	 * Sobrescreva caso queira mudar o comportamento do botão de cancelar
	 * 
	 * @param v
	 */
	protected void onBtnCancelClick(View v) {
		cancel();
	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
	}
}
